Desktop.MemoryWindow = function (_parent, _iconPath, _appName) {
    // Memory specific variables.
    var _rows = 4;
    var _cols = 4;
    var guesses = 0;
    var tiles = RandomGenerator.getPictureArray(_rows, _cols);  // Make a random array using the provided generator and set the tiles.
    var content = undefined; // Set by Memory.prototype.init()

    var tileElements = new Array();
    var lastElementClicked = undefined; // Set by Memory.prototype.tileClicked();

    var timeout = false;
    var scoreCounter = 0;

    // Memory specific properties.
    this.getRows = function () {
        return _rows;
    }

    this.getCols = function () {
        return _cols;
    }

    this.getGuesses = function () {
        return guesses;
    }

    this.updateGuesses = function () {
        guesses++;
    }

    this.resetGuesses = function () {
        guesses = 0;
    }

    this.getTiles = function () {
        return tiles;
    }

    this.generateNewTiles = function () {
        tiles = RandomGenerator.getPictureArray(_rows, _cols);
    }

    this.getContent = function () {
        return content;
    }

    this.setContent = function (divElement) {
        content = divElement;
    }

    this.getTileElements = function () {
        return tileElements;
    }

    this.addTileElement = function (element) {
        tileElements.push(element);
    }

    this.getLastClickedElement = function () {
        return lastElementClicked;
    }

    this.setLastClickedElement = function (lastElement) {
        lastElementClicked = lastElement;
    }

    this.getRunningTimeout = function () {
        return timeout;
    }

    this.setRunningTimeout = function (boolValue) {
        timeout = boolValue;
    }

    this.getScoreCounter = function () {
        return scoreCounter;
    }

    this.updateScoreCounter = function () {
        scoreCounter++;
    }

    this.resetScoreCounter = function () {
        scoreCounter = 0;
    }

    this.getNumberOfTypes = function () {
        return ((_rows * _cols) / 2);
    }

    // Call the base.
    Desktop.Window.call(this, _parent, _iconPath, _appName);
}

Desktop.MemoryWindow.prototype = Desktop.Window.subclassOf(Desktop.Window);

Desktop.MemoryWindow.prototype.createWindowContent = function (_windowReference) {
    // Set the contentContainer
    var content = $(_windowReference).find('.windowContentContainer')[0];
    this.setContent(content);

    // Draw the board.
    this.drawGameBoard();

    // Add container for the restart button and other information.
    this.addInformationContainer(content);
}

Desktop.MemoryWindow.prototype.addInformationContainer = function (content) {
    // Create the infobox.
    var infoBox = document.createElement("div");
    infoBox.className = "infoBox";

    // Create the guess text.
    var guessText = this.createGuessText();

    // Create the restart button.
    var restart = document.createElement("div");
    restart.className = "restartButton";
    restart.textContent = "Restart";
    restart.onselectstart = function () { return false; };
    restart.unselectable = "on";
    restart.style.MozUserSelect = "none";
    restart.style.cursor = "default";

    // Add a click event for the restart button.
    var that = this;
    $(restart).click(function () { that.resetGame(); });

    // Add the content to the infobox.
    infoBox.appendChild(guessText);
    infoBox.appendChild(restart);

    // Add the infoBox to the DOM-structure.
    content.appendChild(infoBox);
}

Desktop.MemoryWindow.prototype.createGuessText = function() {
    // Create the element.
    var guessText = document.createElement("div");
    guessText.className = "guessText";
    guessText.textContent = "Guesses: " + this.getGuesses();
    
    // Return it.
    return guessText;
}

Desktop.MemoryWindow.prototype.drawGameBoard = function () 
{
    // Create the base element.
    var board = document.createElement("div");
    board.className = "board";

    // Create the memory table.
    var tileTable = this.createNewTileTable(this.getRows(), this.getCols());

    // Add it to the board.
    board.appendChild(tileTable);

    // Add it to the DOM-structure.
    this.getContent().appendChild(board);
}

Desktop.MemoryWindow.prototype.createNewTileTable = function (row, col) {
    // Create the table element.
    var table = document.createElement("table");

    for (var rIndex = 0; rIndex < row; rIndex++) {
        // Create the tr element.
        var tr = document.createElement("tr");

        // Create all the td elements.
        for (var cIndex = 0; cIndex < col; cIndex++) {
            // Create the td element.
            var td = document.createElement("td");

            // Create a tile
            var tile = document.createElement("a");
            tile.href = "#";

            // Create the div element that is going to be the picture
            // of the tile and what the user actually clicks on.
            var subElement = document.createElement("div");
            subElement.className = "t0";
            // Add it to the tile.
            tile.appendChild(subElement);

            var that = this;
            // Create an onclick event for the tile.
            tile.onclick = function (e) { that.tileClicked(e); false; };

            // Save the element for later use to distinguish which
            // tile was actually clicked.
            this.addTileElement(subElement);

            // Add the tile to the td element.
            td.appendChild(tile);

            // Add the td element to the tr element.
            tr.appendChild(td);
        }
        // Append the tr element.
        table.appendChild(tr);
    }

    // return the table.
    return table;
}

Desktop.MemoryWindow.prototype.tileClicked = function (e) {
    e = e || event;

    // Get all the tiles.
    var elements = this.getTileElements();

    // Get the clicked element.
    var element = undefined;

    /* 
    If we click with the keyboard we will 
    have the a-tag as the target rather than 
    the child div-tag. Set the child as the
    target if that is the case.
    */
    if (e.target.tagName == "A") {
        element = e.target.firstChild;
    }
    else {
        element = e.target;
    }

    // Get the last element we clicked before this one and get both of the elements index.
    var elementIndex = this.findClickedElementIndex(element);
    var lastElementIndex = this.findClickedElementIndex(this.getLastClickedElement())
    var lastElement = elements[lastElementIndex];

    // Check if the user clicked the same element again.
    if (element == lastElement) {
        return;
    }

    // Check if a timeout is in effect.
    if (this.getRunningTimeout() == true) {
        return;
    }

    // Show the tile.
    element.className = "t" + this.tileElementIdToType(elementIndex).toString();

    // Check if we clicked a tile before.
    if (this.getLastClickedElement() != undefined) {
        // If NOT undefined the user already clicked an element.

        // Since we clicked two elements match them.
        if (this.tileElementIdToType(elementIndex) == this.tileElementIdToType(lastElementIndex)) {
            // If they are equal we have a match.

            // Update the score.
            this.updateScoreCounter();

            // Check if the user won.
            if (this.didUserWin() == true) {
                this.postWinMessage();
                return;
            }

            // If we didn't win remove the eventlisteners.
            element.parentNode.onclick = null;
            lastElement.parentNode.onclick = null;
        }
        else {
            // NO match.

            // Start a timeout.
            this.setRunningTimeout(true)

            // Run the timeout.
            var that = this;
            setTimeout(function () {
                element.className = "t0";
                lastElement.className = "t0";
                that.setRunningTimeout(false);
            }, 1000);

            // Register that we made a wrong guess.
            this.updateGuesses();
            this.updateGuessText();
        }

        /*
        Set the last clicked element to undefined so we 
        reset the count making it so we haven't yet clicked
        a tile.
        */
        this.setLastClickedElement(undefined);
        return;
    }

    // Save the last clicked element.
    this.setLastClickedElement(element);
}

Desktop.MemoryWindow.prototype.tileElementIdToType = function (_index) 
{
    // Set the default value if we can't find the tile.
    var type = -1;

    // Get the tiles.
    var generatedTiles = this.getTiles();

    // Get the type from the tile in the array.
    type = generatedTiles[_index];

    return type;
}

Desktop.MemoryWindow.prototype.findClickedElementIndex = function (_element) 
{
    // Get all the elements for the gameboard.
    var tileElements = this.getTileElements();

    // Go through all the elements to see if you can find the one that was clicked.
    for (var i = 0; i < tileElements.length; i++) 
    {
        if (_element === tileElements[i]) 
        {
            return i;
        }
    }
    return -1;
}

Desktop.MemoryWindow.prototype.didUserWin = function () {
    if (this.getScoreCounter() == this.getNumberOfTypes()) {
        return true;
    }
    return false;
}

Desktop.MemoryWindow.prototype.postWinMessage = function () {
    // Get the content.
    var content = this.getContent();

    // Get the infobox.
    var infoBox = $(content).find('.infoBox')[0];

    // Get the scoreText
    var guessText = $(content).find('.guessText')[0];

    // Remove the text.
    infoBox.removeChild(guessText);

    // Create the win message.
    var winText = document.createElement('div');
    winText.textContent = 'The game is over, you won. Number of guesses: ' + this.getGuesses();
    winText.className = 'winMessage';

    // Add it to the infoBox.
    infoBox.insertBefore(winText, infoBox.firstChild);
}

Desktop.MemoryWindow.prototype.resetGame = function () {
    // Reset what we need to have a fresh game.
    this.resetScoreCounter();
    this.resetGuesses();
    this.generateNewTiles();
    this.resetTiles();
    this.setLastClickedElement(undefined);

    // Get the content.
    var content = this.getContent();
    var infoBox = $(content).find('.infoBox')[0];
    var winMessage = $(content).find('.winMessage')[0];

    // Check if we posted a win message.
    if (winMessage != undefined) {
        // Remove it and then add the score.
        infoBox.removeChild(winMessage);

        var scoreText = this.createGuessText();
        infoBox.insertBefore(scoreText, infoBox.firstChild);
    }
    else {
        this.updateGuessText();
    }
}

Desktop.MemoryWindow.prototype.updateGuessText = function () {
    var content = this.getContent();
    var guessText = $(content).find('.guessText')[0];
    guessText.textContent = "Guesses: " + this.getGuesses();
}

Desktop.MemoryWindow.prototype.resetTiles = function () 
{
    var tileElements = this.getTileElements();
    for (var index = 0; index < tileElements.length; index++) 
    {
        var element = tileElements[index];
        element.className = "t0";
        var that = this;
        // Create an onclick event for the tile.
        element.onclick = function (e) { that.tileClicked(e); false; };
    }
}